package com.xs.ai.controller;

import com.xs.ai.config.LoggingAdvisor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;


/**
 * @author xushu
 * @version 1.0
 * @description:
 */
@RestController
@CrossOrigin
public class OpenAiController {
    private final ChatClient chatClient;

    @Autowired
    private VectorStore vectorStore;

    public OpenAiController(ChatClient.Builder chatClientBuilder, LoggingAdvisor loggingAdvisor, ChatMemory chatMemory, VectorStore vectorStore) {
        this.chatClient = chatClientBuilder
                //日志记录拦截器
                .defaultAdvisors(loggingAdvisor,
                        new PromptChatMemoryAdvisor(chatMemory),
                        new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults())) //RAG
                .defaultSystem("""
                        你是“YunCco(云科)”航空公司的客户聊天⽀持代理。请以友好、乐于助⼈且愉快的⽅式来回复。
                        你正在通过在线聊天系统与客户互动。
                        在操作更改预定或取消预订的操作之前，您必须始终从用户处获取以下信息:预订号、客户姓名。
                        更改预定必须去要求用户提供新的日期、出发地和目的地。
                        在更改预定或退订预定操作之前，请获取改乘客的机票预定详细信息并提醒操作的规则。
                        得到用户确定之后才进行处理机票更改或者处理机票退订操作。
                        在询问用户之前，请检查消息历史记录以获取操作所需要的信息。
                        今天的时间是 {current_date}。
                        请讲中⽂。
                        """)
                .defaultFunctions("cancelBookingRequestFunction","getBookingRequestFunction","updateBookingRequestFunction")// RAG
                .build();
    }

    @CrossOrigin
    @GetMapping(value = "/ai/generateStreamAsString", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> generateStreamAsString(@RequestParam(value = "message", defaultValue = "你好") String message) {
        Flux<String> content = chatClient.prompt()
                .user(message)
                .system(prompt -> prompt.param("current_date", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))))
                //配置内存存放历史记录条数
                .advisors(advisorSpec -> advisorSpec.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
//                .advisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.query(message)))
                .stream()
                .content()
                .concatWith(Flux.just("[complete]"));
        return content;
    }
}
